package com.pinkpig.excel.metadata;

import com.pinkpig.excel.metadata.config.DatabaseConfiguration;
import com.pinkpig.excel.xml.config.TableExportConfiguration;

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author vincenfeng
 */
public class DatabaseTableParser {

    private List<TableMetaData> tableMetaDatas = new ArrayList<>();

    private Map<String, TableMetaData> tableMetaDataMap = new HashMap<>();

    private final String OTHER_CATEGORY = "其他";

    private TableExportConfiguration configuration;

    private DatabaseConfiguration databaseConfiguration;

    public TableMetaData getTableMetaData(String tableName){
        return tableMetaDataMap.get(tableName);
    }

    public List<TableMetaData> getAllTableMetaData(){
        return tableMetaDatas;
    }

    public List<String> getAllTableName(){
        return new ArrayList<String>(tableMetaDataMap.keySet());
    }

    public DatabaseTableParser(TableExportConfiguration configuration){
        this.configuration = configuration;
        this.databaseConfiguration = configuration.getDatabaseConfiguration();
    }

    public void parse() throws SQLException {
        parseTables(databaseConfiguration.getMetaData());
    }



    private void parseTables(DatabaseMetaData databaseMetaData) throws SQLException {
        ResultSet rs = databaseMetaData.getTables(null, null, "%", new String []{"TABLE"});
        while(rs.next()){
            String tableName = rs.getString("TABLE_NAME");
            if(configuration.isExclude(tableName)){
                continue;
            }
            String remarks = rs.getString("REMARKS");
            TableMetaData tableMetaData = new TableMetaData();
            tableMetaData.setTableName(tableName);
            tableMetaData.setRemarks(remarks);
            tableMetaData.setCategory(null==configuration.getCategory(tableName)?OTHER_CATEGORY:configuration.getCategory(tableName));
            tableMetaDatas.add(tableMetaData);
            tableMetaDataMap.put(tableName, tableMetaData);
            parseColumns(tableMetaData, tableName);
            parsePrimaryKeys(databaseMetaData, tableMetaData);
            parseIndexes(databaseMetaData, tableMetaData);
        }
    }

    private void parseColumns(TableMetaData tableMetaData, String tableName) throws SQLException {
        ResultSet rs = databaseConfiguration.getColumns(tableName);
        while(rs.next()){
            String columnName = rs.getString("COLUMN_NAME");
            String dataTypeName = rs.getString("COLUMN_TYPE");
            boolean nullAble = rs.getString("IS_NULLABLE").equals("YES")?true:false;
            String remarks = rs.getString("COLUMN_COMMENT");
            String columnDef = rs.getString("COLUMN_DEFAULT");
            ColumnMetaData columnMetaData = new ColumnMetaData();
            columnMetaData.setColumnName(columnName);
            columnMetaData.setDataTypeName(dataTypeName);
            columnMetaData.setNullAble(nullAble);
            columnMetaData.setRemarks(remarks);
            columnMetaData.setColumnDefault(columnDef);
            tableMetaData.addColumn(columnMetaData);
        }
    }

    private void parsePrimaryKeys(DatabaseMetaData databaseMetaData, TableMetaData tableMetaData) throws SQLException {
        ResultSet rs = databaseMetaData.getPrimaryKeys(null, null, tableMetaData.getTableName());
        PrimaryKeyMetaData primaryKeyMetaData = null;
        while(rs.next()){
            if(null==primaryKeyMetaData){
                primaryKeyMetaData = new PrimaryKeyMetaData();
            }
            String columnName = rs.getString("COLUMN_NAME");
//            String pkName = rs.getString("PK_NAME");
            primaryKeyMetaData.setPkName("PRIMARY KEY");
            primaryKeyMetaData.addPkColumn(tableMetaData.getColumn(columnName));
        }
        if(null!=primaryKeyMetaData){
            tableMetaData.setPrimaryKey(primaryKeyMetaData);
        }
    }

    private void parseIndexes(DatabaseMetaData databaseMetaData, TableMetaData tableMetaData) throws SQLException {
        ResultSet rs = databaseMetaData.getIndexInfo(null, null, tableMetaData.getTableName(), false, true);
        Map<String, IndexMetaData> indexMetaDataMap = new HashMap<>();
        while(rs.next()){
            String indexName = rs.getString("INDEX_NAME");
            if("PRIMARY".equals(indexName)) {
                continue;
            }
            boolean nonUnique = rs.getBoolean("NON_UNIQUE");
            if(!indexMetaDataMap.containsKey(indexName)){
                IndexMetaData indexMetaData = new IndexMetaData();
                indexMetaData.setIndexName(indexName);
                indexMetaData.setUnique(!nonUnique);
                indexMetaDataMap.put(indexName, indexMetaData);
            }
            String columnName = rs.getString("COLUMN_NAME");
            indexMetaDataMap.get(indexName).addIndexColumn(tableMetaData.getColumn(columnName));
        }
        indexMetaDataMap.values().forEach(e -> tableMetaData.addIndex(e));
    }

}
